# 该类为分析的接口函数，主要用于为core主体类提供分析用的算法函数
# 如果需要添加功能，请根据内容添加分析项目
# 流程为： 先设置分析函数->将分析函数添加至ana_setting函数->将函数名称的中文含义添加到translate函数的字典中
import pandas as pd


class Interface:
    def __init__(self):
        self.df = pd.DataFrame()  # 全部数据dataframe
        self.subject = {}   # 学科字典，简称为键名
        self.ana = {}  # 分析配置数组

    @property
    def grade_status(self):
        # 该函数返回 self.grade_analysis , 可以使用 x[subject][type]方法获取年级统计结果
        # 该类需要子类进行重写，当前类不起作用
        return pd.DataFrame()

    # 分析内容的配置， ana1 为科目分析内容 和ana2 为名次对应内容
    def ana_setting(self):
        analysis1 = ['count']  # ['max', 'min', 'mean', 'std', self.excellent, self.passing] 分数列的相关统计
        analysis2 = []  # [self.task, self.task_valid] 名次列的相关统计
        if self.ana.get('max').get():
            analysis1.append('max')
        if self.ana.get('min').get():
            analysis1.append('min')
        if self.ana.get('mean').get():
            analysis1.append('mean')
            analysis1.append(self.compare_rate)
        if self.ana.get('std').get():
            analysis1.append('std')
        if self.ana.get('excellent').get():
            analysis1.append(self.excellent)
            analysis1.append(self.excellent_rate)
            analysis2.append(self.high_rank_student)
            analysis2.append(self.low_rank_student)
        if self.ana.get('pass').get():
            analysis1.append(self.passing)
            analysis1.append(self.passing_rate)
        if self.ana.get('inclusion_single').get():
            analysis2.append(self.task)
        if self.ana.get('inclusion_all').get():
            analysis2.append(self.task_valid)
        return analysis1, analysis2

    # 获取学科总分
    def get_mf(self, subject):  # 获取学科的满分
        return self.subject.get(subject).mf

    # 优秀生 根据排名
    def high_rank_student(self, x: pd.Series):
        if x.count() != 0:
            grade = self.grade_status
            line = self.ana.get('good_line').get()
            subject = x.name[:-2]
            # print(len(grade), subject, subject in grade.columns, grade.columns)
            if grade is not None and (subject in grade.columns):
                total = grade[subject]['count']
                # print(total)
                return x[x <= total*line].count() / x.count() * 100

    # 低分， 根据排名
    def low_rank_student(self, x: pd.Series):
        if x.count() != 0:
            grade = self.grade_status
            line = self.ana.get('low_line').get()
            subject = x.name[:-2]
            # print(len(grade), subject)
            if grade is not None and (subject in grade.columns):
                total = grade[subject]['count']
                return x[x >= total * line].count() / x.count() * 100

    # 优秀 根据分数
    def excellent(self, x: pd.Series):
        if x.count() != 0:
            score = self.get_mf(x.name)
            line = self.ana.get('good_line').get()
            # return x[x >= score * 0.8].value_counts().sum()
            total = x[x >= score * (1-line)].count()
            return total

    # 优秀率, 根据分数
    def excellent_rate(self, x: pd.Series):
        if x.count() != 0:
            score = self.get_mf(x.name)
            line = self.ana.get('good_line').get()
            total = x[x >= score * (1-line)].count()
            return total / x.count() * 100

    # 计算比均率
    def compare_rate(self, x: pd.Series):
        if x.count() != 0:
            grade = self.grade_status
            if grade is not None and (x.name in grade.columns):
                return x.mean() / grade[x.name]['mean'] * 100

    # 计算及格， 根据分数
    def passing(self, x: pd.Series):
        if x.count() != 0:
            score = self.get_mf(x.name)
            return x[x >= score * 0.6].count()

    # 及格率 根据分数
    def passing_rate(self, x: pd.Series):
        if x.count() != 0:
            score = self.get_mf(x.name)
            return x[x >= score * 0.6].count() / x.count() * 100

    # 计算任务指标， 根据排名
    def task(self, x: pd.Series):
        if x.count() != 0:
            task = self.ana.get('task').get()
            if task:
                return x[x <= task].count()
            # print(task, x[x < task].value_counts())

    # 用于计算有效达标， 根据排名
    def task_valid(self, x: pd.Series):  # 用于占位
        return None

    # 翻译列名， 添加了项目后，可自行设置
    def translate(self, df: pd.DataFrame):
        rename_dict = {
            'kh': '考号',
            'xm': '姓名',
            'bj': '班级',
            'name': '科目',
            'count': '考生数',
            # 以下是统计名称
            'max': '最高分',
            'min': '最低分',
            'mean': '平均分',
            'std': '标准差',
            'excellent': '优秀数',
            'excellent_rate': '优秀率',
            'passing': '及格数',
            'passing_rate': '及格率',
            'task': '达标',
            'task_valid': '有效达标',
            'score': '科目得分',
            'high_rank_student': '优生率',
            'low_rank_student': '控差率',
            'compare_rate': '比均率'
        }
        # 根据科目设置，将简称翻译为中文名称
        for key, item in self.subject.items():
            rename_dict[item.jc] = item.title
            rename_dict[item.jc+'mc'] = item.title + '名次'
        df2 = df.rename(columns=rename_dict, index=rename_dict)
        return df2

    # 等级赋分函数，暂未实现
    def wight_score(self, row, jc):
        return row[jc]

    # 执行等级赋分
    def weight_re_score(self):
        for jc, item in self.subject.items():
            if item.state is True:
                self.df[jc+'zh'] = self.df.apply(self.wight_score, args=(jc,), axis=1)

    # 科目教学得分计算
    # 每个项目的获取方式为 row[jc][项目名] ,项目名请参考本页上面translate函数的rename_dict字典
    # 当前算法为  得分 = 比均率 + 优秀率 + 及格率 - 标准差
    # 如需修改请仿照如下改写
    def subject_score(self, row, jc):
        return row[jc]['compare_rate'] + row[jc]['excellent_rate'] + row[jc]['passing_rate'] - row[jc]['std']

    # 计算教师教学得分
    def score(self, df: pd.DataFrame):
        na = list()
        # 创建一个新的双层索引
        multi_index = pd.MultiIndex.from_product([self.subject.keys(), ['score']], names=['学科', '分数'])
        # 对每一个科目将传入的根据dataFrame新增一行数据， 并添加到结果的数组中
        for jc, item in self.subject.items():
            re = df.apply(self.subject_score, args=(jc,), axis=1)
            na.append(re)
        # 将生成的数组组合成新的dataFrame，并转置，添加索引
        df = pd.DataFrame(na).T
        df.columns = multi_index
        # print(df)
        return df



